/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.yonsei.iwb.sdt.refinement.generator;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import java.util.List;
import java.util.Vector;
import org.yonsei.iwb.sdt.algorithm.DCSSearcher;
import org.yonsei.iwb.sdt.datastructure.tree.BranchingType;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import org.yonsei.iwb.sdt.ontology.PropertyArc;
import org.yonsei.iwb.sdt.refinement.CardinalityRestrictionRefinement;
import org.yonsei.iwb.sdt.refinement.ExpandingHistory;
import org.yonsei.iwb.sdt.refinement.ExpandingHistorySet;
import org.yonsei.iwb.sdt.refinement.Refinement;
import org.yonsei.iwb.sdt.refinement.RefinementType;
import org.yonsei.iwb.sdt.util.SDTLog;
import org.yonsei.iwb.sdt.util.UtilFunctions;

/**
 *
 * @author JDK
 */
public class CardinalityRestrictionRefinementMaker extends Thread {

    private Model model;
    private Vector<Resource> instanceSet;
    private PropertyArc pa;
    private int standard;
    private Vector<PropertyArc> history;
    private DecomposeCandidateSet dcs;
    private QuantificationRefinementMaker qrm;

//    private ExpandingHistorySet ehs;
//    private Vector<Resource> css;
    public CardinalityRestrictionRefinementMaker(Model model, Vector<Resource> instanceSet) {
        this.model = model;
        this.instanceSet = instanceSet;
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.CARDINALITYRESTRICTION);

    }

    public CardinalityRestrictionRefinementMaker(Model model, PropertyArc pa, int standard, Vector<PropertyArc> history, Vector<Resource> instanceSet, DecomposeCandidateSet dcs) {
        this.model = model;
        this.instanceSet = instanceSet;
        this.pa = pa;
        this.standard = standard;
        this.history = history;
        this.dcs = dcs;
        this.qrm = new QuantificationRefinementMaker(this.model, RefinementType.CARDINALITYRESTRICTION);
    }

    @Override
    public synchronized void run() {
        long startTime = System.currentTimeMillis();
        boolean gen = decomposeCandidateOfCRR();
        DCSSearcher.FLAGNUM--;
        long endTime = System.currentTimeMillis();
        if (gen) {
            SDTLog.log(SDTLog.DETAIL, "# CRR : Standard = " + standard + " / Property : " + pa.toString() + " is generated..." + ((endTime - startTime) / 1000.0f) + "s)\n");
        } else {
            SDTLog.log(SDTLog.DETAIL, "# - CRR : Standard = " + standard + " / Property : " + pa.toString() + " is NOT generated..." + ((endTime - startTime) / 1000.0f) + "s)\n");
        }

    }

    private boolean decomposeCandidateOfCRR() {
        if (history.isEmpty()) {
            Vector<Refinement> refset = this.refinementGenerator(pa, standard);
            if (refset != null) {
                this.dcs.add(new DecomposeCandidate(refset, pa, RefinementType.CARDINALITYRESTRICTION));
                return true;
            } else {
                return false;
            }
        } else {
            DecomposeCandidateSet newdcs = this.refinementGenerator(pa, standard, history);
            if (newdcs != null) {
                this.dcs.addAll(newdcs);
                return true;
            } else {
                return false;
            }
        }

    }

    public DecomposeCandidateSet refinementGenerator(PropertyArc pa, int standard, Vector<PropertyArc> propertyHistory) {
                
        Vector<Resource> css2;
        if (pa.getDirection()) {
            css2 = this.getSatisfiedInstanceSet(standard, pa);
        } else {
            css2 = this.getInversedSatisfiedInstanceSet(standard, pa);
        }


//        for (int i = 0; i < css2.size(); i++) {
//            System.out.println(" resource = " + css2.get(i));            
//        }
//        System.out.println("standard " + standard);
//        ehs = this.qrm.expandingHistoryCounter(propertyHistory, css2);
        ExpandingHistorySet ehs = this.qrm.expandingHistoryCounter(propertyHistory, css2);
        DecomposeCandidateSet dcs = new DecomposeCandidateSet();

        for (int i = 0; i < ehs.size(); i++) {
            ExpandingHistory eh = ehs.get(i);
            Vector<Refinement> rset = new Vector<Refinement>();
            Refinement pref = new CardinalityRestrictionRefinement(standard, ">", pa, eh);
            Refinement nref = new CardinalityRestrictionRefinement(standard, "<=", pa, eh);
            nref.setBranchingType(BranchingType.NEGATION_TYPE);

            Vector<Resource> is = eh.getInstanceSet();
            Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(this.instanceSet);
            for (int j = 0; j < is.size(); j++) {
                Resource result = is.get(j);
                if (this.instanceSet.contains(result)) {
                    pref.setInstanceSet(result);
                    cloneSet.remove(result);
                }
            }

            if (!pref.getInstanceSet().isEmpty()) {
                rset.add(pref);
            }

            if (!cloneSet.isEmpty()) {
                nref.setInstanceSet(cloneSet);
                rset.add(nref);
            }

            if (!rset.isEmpty()) {
                DecomposeCandidate dc = new DecomposeCandidate(rset, pa, RefinementType.CARDINALITYRESTRICTION);
                dcs.add(dc);
            }
        }

        return dcs;
    }

    public Vector<Refinement> refinementGenerator(PropertyArc pa, int standard) {
        Vector<Refinement> rset = new Vector<Refinement>();
        Vector<Resource> css;
        if (pa.getDirection()) {
            css = this.getSatisfiedInstanceSet(standard, pa);
        } else {
            css = this.getInversedSatisfiedInstanceSet(standard, pa);
        }

        Refinement pref = new CardinalityRestrictionRefinement(standard, ">", pa);
        Refinement nref = new CardinalityRestrictionRefinement(standard, "<=", pa);
        nref.setBranchingType(BranchingType.NEGATION_TYPE);

        Vector<Resource> cloneSet = UtilFunctions.copyInstanceSet(instanceSet);
        for (int i = 0; i < css.size(); i++) {
            Resource result = css.get(i);
            if (this.instanceSet.contains(result)) {
                pref.setInstanceSet(result);
                cloneSet.remove(result);
            }
        }

        if (!pref.getInstanceSet().isEmpty()) {
            rset.add(pref);
        }

        if (!cloneSet.isEmpty()) {
            nref.setInstanceSet(cloneSet);
            rset.add(nref);
        }

        if (cloneSet.isEmpty() && pref.getInstanceSet().isEmpty()) {
            return null;
        }

        return rset;
    }

    private Vector<Resource> getInversedSatisfiedInstanceSet(int standard, PropertyArc pa) {
        Vector<Resource> css = new Vector<Resource>();
        Vector<Resource> result = new Vector<Resource>();

        NodeIterator ni = this.model.listObjectsOfProperty(pa.getProperty());
        while (ni.hasNext()) {
            Resource r = ni.nextNode().asResource();
            if (!css.contains(r)) {
                css.add(r);
            }
        }

        for (int i = 0; i < css.size(); i++) {
            Resource value = css.get(i);
            ResIterator res = this.model.listResourcesWithProperty(pa.getProperty(), value);
            List list = res.toList();
            if (list.size() > standard) {
                result.add(value);
            }
        }
        return result;
    }

    private Vector<Resource> getSatisfiedInstanceSet(int standard, PropertyArc pa) {
        Vector<Resource> css = new Vector<Resource>();
        Vector<Resource> result = new Vector<Resource>();

        ResIterator res = this.model.listResourcesWithProperty(pa.getProperty());
        while (res.hasNext()) {
            Resource r = res.nextResource();
            if (!css.contains(r)) {
                css.add(r);
            }
        }

        for (int i = 0; i < css.size(); i++) {
            Resource value = css.get(i);
            NodeIterator ni = this.model.listObjectsOfProperty(value, pa.getProperty());
            List list = ni.toList();
            if (list.size() > standard) {
                result.add(value);
            }
        }

        return result;
    }
}
